#import "BCWebView.h"
#import <BCFoundation/BCFoundation.h>
#import <Masonry/Masonry.h>
#import "ZHWebBridgeTask.h"
#import "BCRouter.h"

@interface BCWebView ()
<WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler>

@property (nonatomic, strong) NSMutableURLRequest *currentRequest;
@property (nonatomic, strong) NSMutableArray<ZHWebBridgeTask *> *listBridges;
@property (nonatomic, strong) NSMutableDictionary *registerJSObjDict;  //交互的js对象 集合
@property (nonatomic, strong) UIActivityIndicatorView *activityIndicator;
@property (nonatomic, copy) void (^ htmlHeightBlock)(CGFloat height);

@end

@implementation BCWebView

//MARK: - system
- (void)dealloc {
    [self cleanWebView];
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        _listBridges = [[NSMutableArray<ZHWebBridgeTask *> alloc] init];
        _registerJSObjDict = [[NSMutableDictionary alloc] init];

        [self configureSubviews];
    }
    return self;
}

//MARK: - Setter
- (void)setShowIndicator:(BOOL)showIndicator {
    _showIndicator = showIndicator;
    if (!_activityIndicator.superview) {
        [self addSubview:self.activityIndicator];
        [_activityIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
            make.center.mas_equalTo(self);
        }];
    }
    _activityIndicator.hidden = !showIndicator;
}

- (void)setUrl:(NSString *)url {
    _url = url;
    [self restWebViewHeight];
    [self.webView loadRequest:self.currentRequest];
}

- (void)setLocalHtmlString:(NSString *)localHtmlString {
    _localHtmlString = localHtmlString;
//    [self restWebViewHeight];
    //使用本地 html
    [self.webView loadHTMLString:[self loadDataWithMobileHeader] baseURL:nil];
}
- (NSString *)loadDataWithMobileHeader {
    NSString *headString = @"<!DOCTYPE>\n<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">";
    NSString *cssPath = [[NSBundle mainBundle] pathForResource:@"quill.snow" ofType:@"css"];
    NSString *cssString = [NSString stringWithFormat:@"\n<link rel=\"stylesheet\" type=\"text/css\" href=\"%@\">\n",cssPath];
    
    NSString *imageStyleString = @"<style>img {max-width: 100%;text-align:center} body {overflow-y: scroll !important;word-wrap:break-word}</style>";
    NSString *result = [NSString stringWithFormat:@"%@%@%@</head>\n<div class=\"ql-editor\">\n%@\n</div>\n</html>",headString,cssString,imageStyleString,self.localHtmlString];
    
    return result;
}
- (void)setScrollEnabled:(BOOL)scrollEnabled {
    self.webView.scrollView.scrollEnabled = scrollEnabled;
}
// 防止内容很少的时候，webView缺省高度724
- (void)restWebViewHeight {
    CGRect frame = self.webView.frame;
    frame.size.height = 0;
    self.webView.frame = frame;
}

//MARK: - Public
- (void)cleanWebView {
    [_listBridges removeAllObjects];
    if (_webView) {
        _webView.UIDelegate = nil;
        _webView.navigationDelegate = nil;
        [_webView scrollView].delegate = nil;
        [_webView loadHTMLString:@"" baseURL:nil];
        [_webView stopLoading];
        [_webView removeFromSuperview];
        _webView = nil;
    }

    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    [[NSURLCache sharedURLCache] setDiskCapacity:0];
    [[NSURLCache sharedURLCache] setMemoryCapacity:0];
    [[NSURLCache sharedURLCache] removeCachedResponseForRequest:self.currentRequest];
}

- (void)setHtmlHeightComplete:(void (^_Nullable)(CGFloat height))complete {
    self.htmlHeightBlock = complete;
}

//MARK: - SubViews
- (void)configureSubviews {
    [self addSubview:self.webView];
    [_webView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.mas_equalTo(self);
    }];
    //添加默认监听
    [self prepareBridges];
}

//MARK: - 添加js调用oc 的bridge 任务
- (void)prepareBridges {
    //子类重写
    // 添加文件预览桥接
    [self addBridgeHandler:@"filePreview" action:^(NSString *routerUrl) {
        if (routerUrl.length > 0 && [routerUrl isKindOfClass:[NSString class]]) {
            [[BCRouter sharedInstance] pushRoute:routerUrl];
        }
    }];
}

- (void)addBridgeHandler:(NSString *)ObjName action:(void (^)(id msgBody))action {
    ZHWebBridgeTask *bridgeTask = [[ZHWebBridgeTask alloc] init];
    bridgeTask.ObjName = ObjName;
    [bridgeTask setBridgeAction:action];
    [self.listBridges addObject:bridgeTask];
}

//MARK: - oc 调用js
- (void)evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *error))completionHandler {
    [self.webView evaluateJavaScript:javaScriptString completionHandler:completionHandler];
}

//MARK: - WKWebView delegate
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
    if (message.name.length <= 0 || !message.body) {
        return;
    }
    NSString *objName = message.name;
    for (ZHWebBridgeTask *task in self.listBridges) {
        if ([objName isEqualToString:task.ObjName]) {//找到要执行的对象
            // message.body进行了encode操作路由无法解析 需要进行decoded
            NSString *bodyString = [NSString stringWithFormat:@"%@", message.body];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
            NSString *decodedString = (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (__bridge CFStringRef)bodyString, CFSTR(""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
#pragma clang diagnostic pop
            task.bridgeAction(decodedString);
            break;
        }
    }
}

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ? : @"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
        completionHandler();
    }])];
    [self.viewControllerRef presentViewController:alertController animated:YES completion:nil];
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler
{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:message ? : @"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction *_Nonnull action) {
        completionHandler(NO);
    }])];
    [alertController addAction:([UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
        completionHandler(YES);
    }])];
    [self.viewControllerRef presentViewController:alertController animated:YES completion:nil];
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *_Nullable))completionHandler
{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
        textField.text = defaultText;
    }];
    [alertController addAction:([UIAlertAction actionWithTitle:@"完成" style:UIAlertActionStyleDefault handler:^(UIAlertAction *_Nonnull action) {
        completionHandler(alertController.textFields[0].text ? : @"");
    }])];

    [self.viewControllerRef presentViewController:alertController animated:YES completion:nil];
}

//MARK: - WKNavigationDelegate
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (navigationAction.targetFrame == nil) {
        [webView loadRequest:navigationAction.request];
    }
    if (navigationAction.navigationType == WKNavigationTypeLinkActivated) {
        decisionHandler(WKNavigationActionPolicyCancel);
    } else {
        decisionHandler(WKNavigationActionPolicyAllow);
    }
}

// 解决网页中有target="_blank" 在新窗口打开链接的一种方法
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

// 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    if (self.showIndicator) {
        [self.activityIndicator startAnimating];
    }
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
    BCLog(@"[http] load err:%@", [error userInfo]);
    if (self.showIndicator) {
        [self.activityIndicator stopAnimating];
    }
}

// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
    if (self.showIndicator) {
        [self.activityIndicator stopAnimating];
    }
    // 禁止放大缩小
    NSString *injectionJSString = @"var script = document.createElement('meta');"
        "script.name = 'viewport';"
        "script.content=\"width=device-width, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0, user-scalable=no\";"
        "document.getElementsByTagName('head')[0].appendChild(script);";
    [webView evaluateJavaScript:injectionJSString completionHandler:nil];

    //计算出webView滚动视图滚动的高度
    @BCWeakify(self);

    [webView evaluateJavaScript:@"document.body.scrollWidth"completionHandler:^(id _Nullable result, NSError *_Nullable error) {
        CGFloat ratio =  CGRectGetWidth(self.webView.frame) / [result floatValue];

        [webView evaluateJavaScript:@"document.body.scrollHeight"completionHandler:^(id _Nullable result, NSError *_Nullable error) {
            @BCStrongify(self);
            CGFloat htmlHeight = [result floatValue] * ratio;
            if (self.autoHeight) {
                CGRect frame = self.webView.frame;
                frame.size.height = htmlHeight;
                self.webView.frame = frame;
            }

            if (self.htmlHeightBlock) {
                self.htmlHeightBlock(htmlHeight);
            }
        }];
    }];
}

//MARK: - getter
- (WKWebView *)webView {
    if (!_webView) {
        //设置cookies
        __block NSMutableString *cookieStr = [[NSMutableString alloc] init];
        NSArray<NSHTTPCookie *> *cookies = [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies;
        [cookies enumerateObjectsUsingBlock:^(NSHTTPCookie *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
            [cookieStr appendFormat:@"document.cookie='%@=%@;path=/';", obj.name, obj.value];
        }];
        NSString *jScript = (NSString *)cookieStr;

        WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jScript injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:YES];
        WKUserContentController *wkUController = [[WKUserContentController alloc] init];
        [wkUController addUserScript:wkUScript];
        WKWebViewConfiguration *wkWebConfig = [[WKWebViewConfiguration alloc] init];
        wkWebConfig.userContentController = wkUController;

        _webView = [[WKWebView alloc] initWithFrame:self.bounds configuration:wkWebConfig];
        _webView.UIDelegate = self;
        _webView.navigationDelegate = self;
        _webView.backgroundColor = [UIColor clearColor];
        _webView.opaque = NO;
        _webView.scrollView.showsVerticalScrollIndicator = NO;
        if (@available(iOS 11.0, *)) {
            _webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
    }
    return _webView;
}

- (NSMutableURLRequest *)currentRequest {
    if (!_currentRequest && _url) {
        NSURL *requestURL = [NSURL URLWithString:_url];
        if (!requestURL) {
            BCLog(@"[web] error request");
        }
        _currentRequest = [[NSMutableURLRequest alloc] initWithURL:requestURL];
        if (self.headers) {
            for (NSString *key in self.headers.allKeys) {
                NSString *value = self.headers[key];
                if (value.length > 0) {
                    [_currentRequest setValue:value forHTTPHeaderField:key];
                }
            }
        }
    }
    return _currentRequest;
}

- (UIActivityIndicatorView *)activityIndicator {
    if (!_activityIndicator) {
        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        _activityIndicator.center = self.center;
        _activityIndicator.color = [UIColor blackColor];
        _activityIndicator.hidesWhenStopped = YES;
    }
    return _activityIndicator;
}

//MARK:- UIViewController
- (UIViewController *)viewControllerRef {
    id responder = self;
    while (responder) {
        if ([responder isKindOfClass:[UIViewController class]]) {
            return responder;
        }
        responder = [responder nextResponder];
    }
    return nil;
}

@end
